﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Elf32_Half =System.UInt16;
using Elf32_Word = System.UInt32;
using Elf32_Addr = System.UInt32;
using Elf32_Off = System.UInt32;
using Elf32_Sword = System.Int32;
using SceUID = System.Int32;
using uintptr_t = System.UInt32;
using uint32_t = System.UInt32;
using Elf32_Section = System.UInt16;


using size_t = System.UInt32;
using System.IO;
using System.Runtime.InteropServices;

public class Elf : MonoBehaviour
{
    public  string FileName ="" ;
    public int PT_LOAD = 1;
    public int PF_X = (1 << 0);
    public int PF_W = (1 << 1);
    public int PF_R = (1 << 2);
    // Start is called before the first frame update
    unsafe void Start()
    {

        //int res = 0;
        //uintptr_t data_addr = 0;
        //SceUID so_blockid;
        void* so_data;
        //size_t so_size;
        FileStream _fStream = new FileStream(Application.streamingAssetsPath + "/"+FileName, FileMode.Open, FileAccess.Read);
        long len = _fStream.Length;
        byte[] a = new byte[len];
        int n= _fStream.Read(a,0,(int)len);
        if (n!= len)
        {
            Debug.LogWarning("Read LogWarning");
        }
        so_data = (void*)arms.getBytePtr(a);
        so_module* mod = (so_module*)arms.getBytePtr(new byte[sizeof(so_module)]);
        mod->ehdr = ( Elf32_Ehdr*)so_data;
        mod->phdr = (Elf32_Phdr*)((byte*)so_data + mod->ehdr->e_phoff);
        mod->shdr = (Elf32_Shdr*)((byte*)so_data + mod->ehdr->e_shoff);
        mod->shstr = (sbyte*)((sbyte*)so_data + mod->shdr[mod->ehdr->e_shstrndx].sh_offset);

        for (int i = 0; i < mod->ehdr->e_phnum; i++)
        {
            if ((mod->phdr[i].p_flags & PF_X) == PF_X)
            {
                //void* prog_data;
                size_t prog_size;
                prog_size = ALIGN_MEM(mod->phdr[i].p_memsz, mod->phdr[i].p_align);

            }
        }
        for (int i = 0; i < mod->ehdr->e_shnum; i++)
        {
            sbyte* sh_name = mod->shstr + mod->shdr[i].sh_name;
            mod->text_base = mod->phdr[i].p_vaddr;
            mod->text_size = mod->phdr[i].p_memsz;

            uintptr_t sh_addr = mod->text_base + mod->shdr[i].sh_addr;

            size_t sh_size = mod->shdr[i].sh_size;
            if (strcmp(sh_name, ".dynstr") == 0)
            {
                mod->dynstr = (sbyte*)(so_data)+(uint)sh_addr;
                print("dynstr:: "+ new string(mod->dynstr));
            }
            print("count:" + sh_size);
        }

        //for (int i = 0; i < mod->num_dynamic; i++)
        //{
        //    switch (mod->dynamic[i].d_tag)
        //    {
        //        case DT_SONAME:
        //            mod->soname = mod->dynstr + mod->dynamic[i].d_ptr;
        //            print("count:" +new string( mod->soname));
        //            break;
        //        default:
        //            break;
        //    }
        //}
        _fStream.Dispose();
    }

    public const int DT_SONAME = 14;

    public unsafe int strcmp(sbyte* sh_name,string str)
    {
        string t = new string(sh_name);
        print(t );
        if (t.Equals(str))
            return 0;
        else
            return -1;
    }

    size_t ALIGN_MEM(uint x,uint align) {return (((x) + ((align) - 1)) & ~((align) - 1)); }

    // Update is called once per frame
    void Update()
    {
        
    }
}

public unsafe struct so_module
{
    public SceUID text_blockid, data_blockid;
    public uintptr_t text_base, data_base;
    public size_t text_size, data_size;

public Elf32_Ehdr* ehdr;
    public Elf32_Phdr* phdr;
    public Elf32_Shdr* shdr;

    public Elf32_Dyn* dynamic;
    public Elf32_Sym* dynsym;
    public Elf32_Rel* reldyn;
    public Elf32_Rel* relplt;

    //int (** init_array) (void);
    public uint32_t* hash;

    public int num_dynamic;
    public int num_dynsym;
    public int num_reldyn;
    public int num_relplt;
    public int num_init_array;

    public sbyte* soname;
    public sbyte* shstr;
    public sbyte* dynstr;
} ;

[StructLayout(LayoutKind.Explicit)]
public unsafe struct Elf32_Dyn
{
    [FieldOffset(0)] public Elf32_Sword d_tag;            /* Dynamic entry type */

    [FieldOffset(0)] public Elf32_Word d_val;         /* Integer value */
    [FieldOffset(0)] public Elf32_Addr d_ptr;			/* Address value */
  
} ;

public unsafe struct Elf32_Sym
{
    public Elf32_Word st_name;       /* Symbol name (string tbl index) */
    public Elf32_Addr st_value;        /* Symbol value */
    public Elf32_Word st_size;     /* Symbol size */
    public byte st_info;      /* Symbol type and binding */
    public byte st_other;     /* Symbol visibility */
    public Elf32_Section st_shndx;		/* Section index */
} ;

public struct Nums
    {
    public const int EI_NIDENT = 16;
    }

public unsafe struct Elf32_Ehdr
{
    public fixed sbyte e_ident[Nums.EI_NIDENT]; /* Magic number and other info */
    public Elf32_Half e_type;          /* Object file type */
    public Elf32_Half e_machine;       /* Architecture */
    public Elf32_Word e_version;       /* Object file version */
    public Elf32_Addr e_entry;     /* Entry point virtual address */
    public Elf32_Off e_phoff;      /* Program header table file offset */
    public Elf32_Off e_shoff;      /* Section header table file offset */
    public Elf32_Word e_flags;     /* Processor-specific flags */
    public Elf32_Half e_ehsize;        /* ELF header size in bytes */
    public Elf32_Half e_phentsize;     /* Program header table entry size */
    public Elf32_Half e_phnum;     /* Program header table entry count */
    public Elf32_Half e_shentsize;     /* Section header table entry size */
    public Elf32_Half e_shnum;     /* Section header table entry count */
    public Elf32_Half e_shstrndx;		/* Section header string table index */
} 

public unsafe struct Elf32_Rel
{
    public Elf32_Addr r_offset;      /* Address */
    public Elf32_Word r_info;			/* Relocation type and symbol index */
} ;

public unsafe struct Elf32_Phdr
{
    public Elf32_Word p_type;            /* Segment type */
    public Elf32_Off p_offset;     /* Segment file offset */
    public Elf32_Addr p_vaddr;     /* Segment virtual address */
    public Elf32_Addr p_paddr;     /* Segment physical address */
    public Elf32_Word p_filesz;        /* Segment size in file */
    public Elf32_Word p_memsz;     /* Segment size in memory */
    public Elf32_Word p_flags;     /* Segment flags */
    public Elf32_Word p_align;		/* Segment alignment */
} ;

public unsafe struct Elf32_Shdr
{
    public Elf32_Word sh_name;       /* Section name (string tbl index) */
    public Elf32_Word sh_type;     /* Section type */
    public Elf32_Word sh_flags;        /* Section flags */
    public Elf32_Addr sh_addr;     /* Section virtual addr at execution */
    public Elf32_Off sh_offset;        /* Section file offset */
    public Elf32_Word sh_size;     /* Section size in bytes */
    public Elf32_Word sh_link;     /* Link to another section */
    public Elf32_Word sh_info;     /* Additional section information */
    public Elf32_Word sh_addralign;        /* Section alignment */
    public Elf32_Word sh_entsize;		/* Entry size if section holds table */
} ;

